home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 1 / Atari Mega Archive - Volume 1.iso / gnu / gas / gassrc04.zoo / i860.c < prev    next >
C/C++ Source or Header  |  1991-01-24  |  28KB  |  1,143 lines

  1. /* i860.c -- Assemble for the I860
  2.    Copyright (C) 1989 Free Software Foundation, Inc.
  3.  
  4. This file is part of GAS, the GNU Assembler.
  5.  
  6. GAS is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 1, or (at your option)
  9. any later version.
  10.  
  11. GAS is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with GAS; see the file COPYING.  If not, write to
  18. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  19.  
  20.  
  21. #include <stdio.h>
  22. #include <ctype.h>
  23.  
  24. #include "i860-opcode.h"
  25. #include "as.h"
  26. #include "frags.h"
  27. #include "struc-symbol.h"
  28. #include "flonum.h"
  29. #include "expr.h"
  30. #include "hash.h"
  31. #include "md.h"
  32. #include "i860.h"    /* position dependent redefine */
  33. #include "write.h"
  34. #include "read.h"
  35. #include "symbols.h"
  36.  
  37. void md_begin();
  38. void md_end();
  39. void md_number_to_chars();
  40. void md_assemble();
  41. char *md_atof();
  42. void md_convert_frag();
  43. void md_create_short_jump();
  44. void md_create_long_jump();
  45. int  md_estimate_size_before_relax();
  46. void md_number_to_imm();
  47. void md_number_to_disp();
  48. void md_number_to_field();
  49. void md_ri_to_chars();
  50. static void i860_ip();
  51. void emit_relocations();
  52.  
  53. const relax_typeS md_relax_table[] = { 0 };
  54.  
  55. /* handle of the OPCODE hash table */
  56. static struct hash_control *op_hash = NULL;
  57.  
  58. static void s_dual(), s_enddual();
  59. static void s_atmp();
  60.  
  61. const pseudo_typeS
  62. md_pseudo_table[] = {
  63.     { "dual",       s_dual,     4 },
  64.     { "enddual",    s_enddual,  4 },
  65.     { "atmp",        s_atmp,    4 },
  66.     { NULL,         0,          0 },
  67. };
  68.  
  69. int md_short_jump_size = 4;
  70. int md_long_jump_size = 4;
  71. int omagic  =  OMAGIC;  /* Magic number for header */
  72.  
  73. /* This array holds the chars that always start a comment.  If the
  74.     pre-processor is disabled, these aren't very useful */
  75. char comment_chars[] = "!/";    /* JF removed '|' from comment_chars */
  76.  
  77. /* This array holds the chars that only start a comment at the beginning of
  78.    a line.  If the line seems to have the form '# 123 filename'
  79.    .line and .file directives will appear in the pre-processed output */
  80. /* Note that input_file.c hand checks for '#' at the beginning of the
  81.    first line of the input file.  This is because the compiler outputs
  82.    #NO_APP at the beginning of its output. */
  83. /* Also note that '/*' will always start a comment */
  84. char line_comment_chars[] = "#/";
  85.  
  86. /* Chars that can be used to separate mant from exp in floating point nums */
  87. char EXP_CHARS[] = "eE";
  88.  
  89. /* Chars that mean this number is a floating point constant */
  90. /* As in 0f12.456 */
  91. /* or    0d1.2345e12 */
  92. char FLT_CHARS[] = "rRsSfFdDxXpP";
  93.  
  94. /* Also be aware that MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT may have to be
  95.    changed in read.c .  Ideally it shouldn't have to know about it at all,
  96.    but nothing is ideal around here.
  97.  */
  98. int size_reloc_info = sizeof(struct relocation_info);
  99.  
  100. static unsigned char octal[256];
  101. #define isoctal(c)  octal[c]
  102. static unsigned char toHex[256];
  103.  
  104. struct i860_it {
  105.     char    *error;
  106.     unsigned long opcode;
  107.     struct nlist *nlistp;
  108.     expressionS exp;
  109.     int pcrel;
  110.     enum expand_type expand;
  111.     enum highlow_type highlow;
  112.     enum reloc_type reloc;
  113. } the_insn;
  114.  
  115. #ifdef __STDC__
  116. static void print_insn(struct i860_it *insn);
  117. static int getExpression(char *str);
  118. #else
  119. static void print_insn();
  120. static int getExpression();
  121. #endif
  122. static char *expr_end;
  123. static char last_expand;    /* error if expansion after branch */
  124.  
  125. enum dual
  126. {
  127.     DUAL_OFF = 0, DUAL_ON, DUAL_DDOT, DUAL_ONDDOT,
  128. };
  129. static enum dual dual_mode = DUAL_OFF;    /* dual-instruction mode */
  130.  
  131. static void
  132. s_dual()    /* floating point instructions have dual set */
  133. {
  134.     dual_mode = DUAL_ON;
  135. }
  136.  
  137. static void
  138. s_enddual()    /* floating point instructions have dual set */
  139. {
  140.     dual_mode = DUAL_OFF;
  141. }
  142.  
  143. static int atmp = 31; /* temporary register for pseudo's */
  144.  
  145. static void
  146. s_atmp()
  147. {
  148.     register int temp;
  149.     if (strncmp(input_line_pointer, "sp", 2) == 0) {
  150.       input_line_pointer += 2;
  151.       atmp = 2;
  152.     }
  153.     else if (strncmp(input_line_pointer, "fp", 2) == 0) {
  154.       input_line_pointer += 2;
  155.       atmp = 3;
  156.     }
  157.     else if (strncmp(input_line_pointer, "r", 1) == 0) {
  158.       input_line_pointer += 1;
  159.       temp = get_absolute_expression();
  160.       if (temp >= 0 && temp <= 31)
  161.           atmp = temp;
  162.         else
  163.             as_warn("Unknown temporary pseudo register");
  164.     }
  165.     else {
  166.         as_warn("Unknown temporary pseudo register");
  167.     }
  168.     demand_empty_rest_of_line();
  169.     return;
  170. }
  171.  
  172. /* This function is called once, at assembler startup time.  It should
  173.    set up all the tables, etc. that the MD part of the assembler will need.  */
  174. void
  175. md_begin()
  176. {
  177.   register char *retval = NULL;
  178.   int lose = 0;
  179.   register unsigned int i = 0;
  180.  
  181.   op_hash = hash_new();
  182.   if (op_hash == NULL)
  183.     as_fatal("Virtual memory exhausted");
  184.  
  185.   while (i < NUMOPCODES)
  186.     {
  187.       const char *name = i860_opcodes[i].name;
  188.       retval = hash_insert(op_hash, name, &i860_opcodes[i]);
  189.       if(retval != NULL && *retval != '\0')
  190.     {
  191.       fprintf (stderr, "internal error: can't hash `%s': %s\n",
  192.            i860_opcodes[i].name, retval);
  193.       lose = 1;
  194.     }
  195.       do
  196.     {
  197.       if (i860_opcodes[i].match & i860_opcodes[i].lose)
  198.         {
  199.           fprintf (stderr, "internal error: losing opcode: `%s' \"%s\"\n",
  200.                i860_opcodes[i].name, i860_opcodes[i].args);
  201.           lose = 1;
  202.         }
  203.       ++i;
  204.     } while (i < NUMOPCODES
  205.          && !strcmp(i860_opcodes[i].name, name));
  206.     }
  207.  
  208.   if (lose)
  209.     as_fatal ("Broken assembler.  No assembly attempted.");
  210.  
  211.   for (i = '0'; i < '8'; ++i)
  212.     octal[i] = 1;
  213.   for (i = '0'; i <= '9'; ++i)
  214.     toHex[i] = i - '0';
  215.   for (i = 'a'; i <= 'f'; ++i)
  216.     toHex[i] = i + 10 - 'a';
  217.   for (i = 'A'; i <= 'F'; ++i)
  218.     toHex[i] = i + 10 - 'A';
  219. }
  220.  
  221. void
  222. md_end()
  223. {
  224.     return;
  225. }
  226.  
  227. void
  228. md_assemble(str)
  229.     char *str;
  230. {
  231.     char *toP;
  232.     int rsd;
  233.     int no_opcodes = 1;
  234.     int i;
  235.     struct i860_it pseudo[3];
  236.  
  237.     assert(str);
  238.     i860_ip(str);
  239.  
  240.     /* check for expandable flag to produce pseudo-instructions */
  241.     if (the_insn.expand != 0 && the_insn.highlow == NO_SPEC) {
  242.     for (i = 0; i < 3; i++)
  243.         pseudo[i] = the_insn;
  244.  
  245.     switch (the_insn.expand) {
  246.  
  247.     case E_DELAY:
  248.         no_opcodes = 1;
  249.         break;
  250.  
  251.     case E_MOV:
  252.         if (the_insn.exp.X_add_symbol == NULL &&
  253.             the_insn.exp.X_subtract_symbol == NULL &&
  254.         (the_insn.exp.X_add_number < (1 << 15) &&
  255.          the_insn.exp.X_add_number >= -(1 << 15)))
  256.         break;
  257.         /* or l%const,r0,ireg_dest */
  258.         pseudo[0].opcode = (the_insn.opcode & 0x001f0000) | 0xe4000000;
  259.         pseudo[0].highlow = PAIR;
  260.         /* orh h%const,ireg_dest,ireg_dest */
  261.         pseudo[1].opcode = (the_insn.opcode & 0x03ffffff) | 0xec000000 |
  262.         ((the_insn.opcode & 0x001f0000) << 5);
  263.         pseudo[1].highlow = HIGH;
  264.         no_opcodes = 2;
  265.         break;
  266.  
  267.     case E_ADDR:
  268.         if (the_insn.exp.X_add_symbol == NULL &&
  269.             the_insn.exp.X_subtract_symbol == NULL)
  270.         break;
  271.         /* orh ha%addr_expr,r0,r31 */
  272.         pseudo[0].opcode = 0xec000000 | (atmp<<16);
  273.         pseudo[0].highlow = HIGHADJ;
  274.         pseudo[0].reloc = LOW0;    /* must overwrite */
  275.         /* l%addr_expr(r31),ireg_dest */
  276.         pseudo[1].opcode = (the_insn.opcode & ~0x003e0000) | (atmp << 21);
  277.         pseudo[1].highlow = PAIR;
  278.         no_opcodes = 2;
  279.         break;
  280.  
  281.     case E_U32:    /* 2nd version emulates Intel as, not doc. */
  282.         if (the_insn.exp.X_add_symbol == NULL &&
  283.             the_insn.exp.X_subtract_symbol == NULL &&
  284.         (the_insn.exp.X_add_number < (1 << 16) &&
  285.          the_insn.exp.X_add_number >= 0))
  286.         break;
  287.         /* $(opcode)h h%const,ireg_src2,ireg_dest
  288.         pseudo[0].opcode = (the_insn.opcode & 0xf3ffffff) | 0x0c000000; */
  289.         /* $(opcode)h h%const,ireg_src2,r31 */
  290.         pseudo[0].opcode = (the_insn.opcode & 0xf3e0ffff) | 0x0c000000 |
  291.         (atmp << 16);
  292.         pseudo[0].highlow = HIGH;
  293.         /* $(opcode) l%const,ireg_dest,ireg_dest
  294.         pseudo[1].opcode = (the_insn.opcode & 0xf01f0000) | 0x04000000 |
  295.         ((the_insn.opcode & 0x001f0000) << 5); */
  296.         /* $(opcode) l%const,r31,ireg_dest */
  297.         pseudo[1].opcod